package com.fast.develop.dm.integration.context;

import com.fast.develop.dm.core.context.ModuleContext;
import com.fast.develop.dm.core.event.ContextStartedEvent;
import com.fast.develop.dm.core.event.ContextStoppedEvent;
import com.fast.develop.dm.core.event.ModuleEvent;
import com.fast.develop.dm.core.listener.ModuleListener;
import com.fast.develop.dm.core.persistence.DomainModelManager;
import com.fast.develop.dm.core.registry.ModuleRegistry;
import com.fast.develop.dm.core.properties.DomainRuntimeProperties;
import com.fast.develop.dm.integration.HibernateModuleConfiguration;
import com.fast.develop.dm.integration.orm.DomainModelSessionManager;
import com.fast.develop.dm.integration.web.DomainModelResourcesRest;
import com.fast.develop.dm.integration.web.DomainRequestMappingHandlerMapping;
import com.fast.develop.dm.meta.exception.DomainModelException;
import lombok.SneakyThrows;
import org.springframework.context.ApplicationContext;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 莫寅
 * @createTime 2022-06-07 13:22
 * @desc：
 */
public class DefaultModuleContext implements ModuleContext {

    Map<Class, Object> beans = new HashMap();

    private RequestMappingHandlerMapping requestMappingHandlerMapping;
    private DomainRuntimeProperties domainRuntimeProperties;
    private DomainModelResourcesRest domainModelResourcesRest;
    private DomainModelManager domainModelManager;
    private LocalSessionFactoryBean localSessionFactoryBean;
    private DomainRequestMappingHandlerMapping domainRequestMappingHandlerMapping;

    private boolean enableResourcesRest = false;
    private boolean initialized = false;
    private ApplicationContext applicationContext;
    private ModuleRegistry pluginRegistry;

    public DefaultModuleContext(ApplicationContext applicationContext, ModuleRegistry pluginRegistry, HibernateModuleConfiguration domainRuntimeConfiguration, RequestMappingHandlerMapping requestMappingHandlerMapping) {
        this.requestMappingHandlerMapping = requestMappingHandlerMapping;
        this.domainRuntimeProperties = domainRuntimeConfiguration.getDomainRuntimeProperties();
        this.localSessionFactoryBean = domainRuntimeConfiguration.getLocalSessionFactoryBean();
        this.enableResourcesRest = domainRuntimeConfiguration.enableResourcesRest();
        this.applicationContext = applicationContext;
        this.pluginRegistry = pluginRegistry;
    }


    public void refresh(){
        initialize();

        start();
    }



    @SneakyThrows
    private void initialize(){
        if(initialized){
            throw new DomainModelException("已初始化！");
        }

        enableHibernate();
        initDomainModelManager();
        enableRequestMapping();



        beans.put(RequestMappingHandlerMapping.class, requestMappingHandlerMapping);
        beans.put(DomainRuntimeProperties.class, domainRuntimeProperties);
        beans.put(DomainModelResourcesRest.class, domainModelResourcesRest);
        beans.put(DomainModelManager.class, domainModelManager);
        beans.put(LocalSessionFactoryBean.class, localSessionFactoryBean);

        initialized = true;
    }



    private void initDomainModelManager(){
        this.domainModelManager = new DomainModelSessionManager(localSessionFactoryBean.getObject().openSession());
    }

    private void enableHibernate() throws Exception{
        localSessionFactoryBean.afterPropertiesSet();
    }

    private void enableRequestMapping(){
        if(enableResourcesRest){
            this.domainModelResourcesRest = new DomainModelResourcesRest(domainModelManager);
        }

        this.domainRequestMappingHandlerMapping = new DomainRequestMappingHandlerMapping(domainRuntimeProperties, requestMappingHandlerMapping, domainModelResourcesRest);
        domainRequestMappingHandlerMapping.registerResourcesMapping();
    }


    @Override
    public String getId() {
        return null;
    }

    @Override
    public String getModuleName() {
        return null;
    }

    @Override
    public <T> T getBean(Class<T> tClass) {
        return (T) beans.get(tClass);
    }

    @Override
    public DomainModelManager getDomainModelManager() {
        return domainModelResourcesRest.getdomainModelManager();
    }


    public void destroy(){

        localSessionFactoryBean.destroy();
        domainRequestMappingHandlerMapping.unRegisterResourcesMapping();

        stop();
    }

    private void start() {
        ContextStartedEvent contextStartedEvent = new ContextStartedEvent(this);
        publishEvent(contextStartedEvent);
    }

    private void stop() {
        ContextStoppedEvent contextStoppedEvent = new ContextStoppedEvent(this);
        publishEvent(contextStoppedEvent);
    }



    public void publishEvent(ModuleEvent event) {
        if(pluginRegistry == null){
            return;
        }

        List<ModuleListener> listeners = pluginRegistry.getModuleListeners(ContextStartedEvent.class);
        if(listeners != null){
            for (ModuleListener listener : listeners) {
                listener.onEvent(event);
            }
        }

    }



}
